package com.sunxd.limit.core.support;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.sunxd.limit.core.AbstractLimitHandler;
import com.sunxd.limit.core.annotation.LimitAnnotation;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * @author sun.xd
 * @description: description
 * @date 2024/10/23 19:27
 */
@Component
public class LimitHandlerSupport implements ApplicationContextAware {

    private static Map<String, AbstractLimitHandler> HANDLER_MAP = Maps.newHashMap();

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        Map<String, Object> beansWithAnnotation = applicationContext.getBeansWithAnnotation(LimitAnnotation.class);
        Map<String, List<AbstractLimitHandler>> mapList = Maps.newHashMap();
        for (Object bean : beansWithAnnotation.values()) {
            if (bean instanceof AbstractLimitHandler) {
                LimitAnnotation annotation = bean.getClass().getAnnotation(LimitAnnotation.class);
                if (mapList.containsKey(annotation.group())) {
                    mapList.get(annotation.group()).add((AbstractLimitHandler) bean);
                } else {
                    mapList.put(annotation.group(), Lists.newArrayList((AbstractLimitHandler) bean));
                }
            }
        }
        for (Map.Entry<String, List<AbstractLimitHandler>> next : mapList.entrySet()) {
            List<AbstractLimitHandler> limitHandlers = next.getValue();
            limitHandlers.sort(Comparator.comparing(this::findOrder));
            int size = limitHandlers.size();
            for (int i = 0; i < size; i++) {
                if (i == size - 1) {
                    limitHandlers.get(i).setNextHandler(null);
                } else {
                    limitHandlers.get(i).setNextHandler(limitHandlers.get(i + 1));
                }
            }
            HANDLER_MAP.put(next.getKey(), limitHandlers.get(0));
        }
    }


    private Integer findOrder(Object obj) {
        Order order = obj.getClass().getAnnotation(Order.class);
        return Objects.isNull(order) ? Integer.MAX_VALUE : order.value();
    }


    public static AbstractLimitHandler getHandler(String group){
        return HANDLER_MAP.get(group);
    }

}
